#ifndef _MINI_SRV_H_
#define _MINI_SRV_H_

#include <stdint.h>
#include <pthread.h>

#include <sys/queue.h>

#ifdef __linux__
#include <sys/epoll.h>
#define USE_EPOLL 1
#else
#include <sys/event.h>
#define USE_KQUEUE 1
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define fetch_and_sub(value, cnt) __sync_fetch_and_sub(value, cnt)
#define fetch_and_add(value, cnt) __sync_fetch_and_add(value, cnt)

//// list
//#define LIST_NODE(type) type *prev, *next
//#define LIST_INIT(HEAD) do{(HEAD)->prev=(HEAD)->next=(HEAD);}while(0);
//#define INSERT_LIST(ITEM, PREV, NEXT)do{(ITEM)->prev=(PREV);(ITEM)->next=(NEXT);(PREV)->next=(ITEM);(NEXT)->prev=(ITEM);}while(0);
//#define INSERT_HEAD(ITEM, HEAD) INSERT_LIST((ITEM), (HEAD),(HEAD)->next);
//#define INSERT_TAIL(ITEM, HEAD) INSERT_LIST((ITEM), (HEAD)->prev,(HEAD));
//#define REMOVE_ITEM(ITEM) do{(ITEM)->prev->next=(ITEM)->next;(ITEM)->next->prev=(ITEM)->prev;(ITEM)->prev=(ITEM)->next=(ITEM);}while(0);
//#define LIST_EACH(ITEM, HEAD) for((ITEM)=(HEAD)->next;(ITEM)!=(HEAD);(ITEM)=(ITEM)->next)
//#define LIST_EACH_SAFE(ITEM, TEMP, HEAD) for((ITEM)=(HEAD)->next;(ITEM)!=(HEAD)&&((TEMP)=(ITEM)->next);(ITEM)=(TEMP))
//#define LIST_REPLACE(OLD, NEW) do{(NEW)->next=(OLD)->next;(NEW)->prev=(OLD)->prev;(OLD)->next->prev=(NEW);(OLD)->prev->next=(NEW);}while(0);


struct ev_log_s;
struct ev_loop_s;
struct ev_tcp_s;

enum { EV_UNKNOW = 0, EV_TCP, EV_ASYNC };

typedef int(*array_each_t)(void*, void*);
typedef int (*tcp_cb_pt)(struct ev_tcp_s* );

#define EV_LOG_ERROR 1
#define EV_LOG_INFO 2
#define EV_LOG_DEBUG 3

#define EV_LOG_MAX_LEN 1024
#define EV_MAX_PATH_LEN 256

#define DEFAULT_POOL_SIZE "default_pool_size"
#define MAX_THREAD "max_thread"
#define SERV_PORT "serv_port"
#define MAX_CONNECTS "max_conn"
#define LOG_FILE_PATH "log_file"
#define PID_FILE_PATH "pid_file"
#define BUF_TRUNK_SIZE "buf_trunk_size"
#define MAX_TIMEOUT "max_timeout"
#define DAEMON "daemon"

typedef struct ev_config_s {
    int max_nthread;
    int max_nconnect;
    int max_nwork_thread;
    int default_npool;
    int daemon;
    int log_level;
    int max_timeout;
    size_t buf_trunk_size;
    uint16_t port;
    char logfile[EV_MAX_PATH_LEN];
    char pidfile[EV_MAX_PATH_LEN];
} ev_config_t;


#define kEventRead 1
#define kEventWrite 2
#define kEventError 4
#define kEventAll (kEventRead | kEventWrite)

#define kEventOpAdd 1
#define kEventOpDel 2


typedef int (*event_cb_pt)(void *, uint32_t);

typedef struct ev_event_s {
    int evfd;
    int nevents;
    event_cb_pt ev_cb;
#if USE_KQUEUE
    struct kevent* events;
#else
    struct epoll_event* events;
#endif
}ev_event_t;

typedef struct ev_array_s {
	size_t size;
	uint32_t nelem;
	uint32_t nalloc;
	void *elem;
} ev_array_t;

#define NULL_ARRAY { 0, 0, 0, NULL }

typedef struct ev_log_s {
    int fd;
    int level;
}ev_log_t;

typedef struct ev_buf_s {
    char* buf;
    size_t total;
    size_t offset;
    size_t len;
}ev_buf_t;

typedef struct ev_job_s {
	void* ptr;
    int (*cb)(void*);
} ev_job_t;

typedef struct ev_thread_pool_s {
    int exit;
    int idle_cnt;
    int thread_cnt;
    int init_queue_cnt;
    pthread_cond_t cond;
    pthread_mutex_t mtx;
    ev_array_t jobs;
    pthread_t thread[0];
} ev_thread_pool_t;

typedef struct ev_timer_s {
	int64_t expire;
	int32_t repeat;
	int32_t rotation;
    uint32_t slot;
	ev_job_t job;
	void* data;
    //LIST_NODE(struct ev_timer_s);
    TAILQ_ENTRY(ev_timer_s) node;
} ev_timer_t;

typedef TAILQ_HEAD(, ev_timer_s) ev_timer_head_t;

typedef struct ev_timer_mgr_s {
	size_t granularity;
	int32_t index;
    int32_t slots;
	int64_t update_time;
	ev_array_t timer_slots;
} ev_timer_mgr_t;



#define EV_STREAM_BASE  \
    int fd;             \
    int stop;           \
    int refc;           \
    int type;           \
    int recv_active;    \
    int send_active;    \
    void* data;         \
    struct ev_loop_s* ev;\
    TAILQ_ENTRY(ev_stream_s) node


typedef struct ev_stream_s {
    EV_STREAM_BASE;
}ev_stream_t;

typedef TAILQ_HEAD(, ev_stream_s) ev_stream_head_t;

typedef struct ev_tcp_s
{
    EV_STREAM_BASE;
    int timeout;
    ev_buf_t* in_buf;
    ev_buf_t* out_buf;

    TAILQ_ENTRY(ev_tcp_s) timeout_tqe;
	
    tcp_cb_pt connect_cb;
    tcp_cb_pt read_cb;
    tcp_cb_pt write_cb;
    tcp_cb_pt stop_cb;
    tcp_cb_pt free_cb;

    unsigned connecting:1;
    unsigned connected:1;
} ev_tcp_t;

typedef TAILQ_HEAD(, ev_tcp_s) ev_tcp_list_t;

typedef struct ev_async_s {
    EV_STREAM_BASE;
    int wfd;
    ev_array_t watch_jobs;
    pthread_mutex_t watch_mtx;
} ev_async_t;


typedef struct ev_loop_s
{
    int exit;
    int nstreams;
    pthread_mutex_t stream_mtx;

	ev_array_t pending_jobs;
	pthread_mutex_t pending_mtx;

    pthread_t cur_thread;
    ev_event_t* evp;
    ev_timer_mgr_t* timer_mgr;
    ev_stream_head_t streams_list;
    ev_tcp_list_t streams_timeout;
} ev_loop_t;

// util
int64_t ev_usec_now();
int64_t ev_msec_now();
int ev_socket_nonblocing(int fd);
int ev_socket_reuseaddr(int fd);
int ev_socket_nodelay(int fd);
int ev_socket_keepalive(int fd);
int ev_socket_listen(const char* ip, uint16_t port);
void ev_daemon();

// log 
ev_log_t* ev_log_init(int level, char *filename);
void ev_log_finit(ev_log_t* self);
void ev_log_write(ev_log_t* self, int level, const char* fmt, ...);

#define LOG_SAFE(fmt, ...) ev_log_write(NULL, EV_LOG_DEBUG, fmt, ##__VA_ARGS__)
#define LOG(fmt, ...) ev_log_write(ev_default_log(), EV_LOG_DEBUG, fmt, ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) ev_log_write(ev_default_log(), EV_LOG_INFO, fmt, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) ev_log_write(ev_default_log(), EV_LOG_ERROR, fmt, ##__VA_ARGS__)

#define LOG_ENTER_FN LOG("enter %s", __FUNCTION__)


// array
ev_array_t* ev_array_new(uint32_t alloc_size, size_t elem_size);
void ev_array_del(ev_array_t *a);
int ev_array_init(ev_array_t *a, uint32_t alloc_size, size_t elem_size);
void ev_array_deinit(ev_array_t *a);
void* ev_array_get(ev_array_t *a, uint32_t idx);
static inline uint32_t ev_array_n(ev_array_t* a) { return a->nelem; }
void* ev_array_push(ev_array_t* a);
void* ev_array_pop(ev_array_t* a);
void ev_array_swap(ev_array_t *a, ev_array_t *b);
void* array_get(ev_array_t *a, uint32_t idx);
int ev_array_each(ev_array_t* a, array_each_t func, void* data);


// buf
ev_buf_t* ev_buf_new(const char* data, size_t size);
ev_buf_t* ev_buf_new2(size_t size);
void ev_buf_del(ev_buf_t* self);
void ev_buf_resize(ev_buf_t* self, size_t n);
size_t ev_buf_append(ev_buf_t* self, const char* data, size_t size);
int ev_buf_empty(ev_buf_t* self);
void ev_buf_clear(ev_buf_t* self);
size_t ev_buf_seek(ev_buf_t* self, size_t n);
size_t ev_buf_size(ev_buf_t* self);
const char* ev_buf_lock(ev_buf_t* self);


// timer manager
ev_timer_mgr_t* ev_timer_mgr_new(size_t slots, int granularity);
void ev_timer_mgr_del(ev_timer_mgr_t* mgr);
int ev_timer_mgr_start_timer(ev_timer_mgr_t* mgr, ev_timer_t* t, int64_t expire, int repeate);
int ev_tiemr_mgr_stop_timer(ev_timer_mgr_t* mgr, ev_timer_t* t);
int ev_timer_mgr_tick(ev_timer_mgr_t* mgr, int64_t now);


// stream
void ev_stream_del(ev_stream_t* c);

ev_tcp_t* ev_tcp_new(ev_loop_t* ev, int fd);
ev_tcp_t* ev_tcp_connect(ev_loop_t* ev, const char* ip, uint16_t port);
size_t ev_tcp_write(ev_tcp_t* self, const char* data, size_t len);

ev_async_t* ev_async_new(ev_loop_t* ev);
int ev_async_post(ev_async_t* async, ev_job_t* op);

// timeout op
void ev_add_timeout_watch(ev_tcp_t* c);
void ev_del_timeout_watch(ev_tcp_t* c);
void ev_reset_timeout_watch(ev_tcp_t* c);


// loop
ev_loop_t* ev_loop_new();
void ev_loop_del(ev_loop_t* ev);
void ev_loop_put_pending_queue(ev_loop_t* ev, ev_job_t* op);
void ev_loop_put_stream(ev_loop_t* ev, ev_stream_t* c, int put_tail);
void ev_loop_remove_stream(ev_loop_t* ev, ev_stream_t* c);
int ev_loop_accept(ev_loop_t* ev, int sfd);

// thread pool
ev_thread_pool_t* ev_thread_pool_new(int nthread);
void ev_thread_pool_destroy(ev_thread_pool_t* pool);
void ev_thread_pool_post(ev_thread_pool_t* self, ev_job_t* op);


// event
ev_event_t* ev_event_new(int nevensts, event_cb_pt cb);
void ev_event_destroy(ev_event_t* self);
int ev_event_add_in(ev_event_t* self, int fd, ev_stream_t* c);
int ev_event_del_in(ev_event_t* self, int fd, ev_stream_t* c);
int ev_event_add_out(ev_event_t* self, int fd, ev_stream_t* c);
int ev_event_del_out(ev_event_t* self, int fd, ev_stream_t* c);
int ev_event_add_all(ev_event_t* self, int fd, ev_stream_t* c);
int ev_event_poll(ev_event_t* self, int timeout);
int ev_event_resize(ev_event_t* self, int n);

ev_log_t* ev_default_log();
ev_config_t* ev_default_config();
ev_thread_pool_t* ev_default_thread_pool();


// server
typedef struct ev_server_s {
    int sfd;
    int exit;
    int total_connect;
    ev_event_t* evbase;
    ev_loop_t** evloop;
}ev_server_t;

typedef int(*pre_server_run_pt)(ev_server_t* server);
int ev_server_run(const char* config_filepath, pre_server_run_pt pre_run);



#ifdef __cplusplus
}
#endif

#endif
